// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

#include "fortunethread.h"

#include <QtNetwork>

//! [0]
FortuneThread::FortuneThread(int socketDescriptor, const QString &fortune, const QString &name, QObject *parent)
    : QThread(parent), socketDescriptor(socketDescriptor), text(fortune)
{
    /*这么写也行：
    socketDescriptor= socketDescriptor;
    text= fortune;
    */
    qDebug()<< "FortuneServer()"<< QThread::currentThreadId();
    bin_file_name_path= fortune;
    bin_file_name= name; //
    qDebug()<<QString("bin_file_name")<< bin_file_name_path<< bin_file_name;
}

FortuneThread::~FortuneThread()
{
    qDebug("thread exit");
}
//! [0]


/*用野火多功能调试助手下的网络调试助手，效果比“sscom5.13.1.exe”好很多。在接收152KB数据时，前者瞬间完成（符合实际），后者显示特别慢。
*/
//! [1]
void FortuneThread::run()
{
    /*创建连接的方式：
     * 1. QTcpSocket socket; socket.setSocketDescriptor(n)。 n是由QTcpServer的incomingConnection(n)提供的，n为描述符。
     * 2. QTcpSocket clientConnection = tcpServer->nextPendingConnection(); 获取了描述符。
    */
    QTcpSocket tcpSocket;   //为什么不定义成类成员呢？
    Sta_server sta= Sta_server::WaitPwd;
    QFile file;
    QString str_err;
    qDebug()<< "FortuneRun()"<< QThread::currentThreadId();

//! [1] //! [2]
    if (!tcpSocket.setSocketDescriptor(socketDescriptor)) {
        emit error(tcpSocket.error());
        return;
    }

    connect(&tcpSocket, &QIODevice::bytesWritten, this, &FortuneThread::DataWritten);
    //connect(&tcpSocket, SIGNAL(error_str), this, SLOT(disp_err)); //tcpSocket没有error_str信号。
    //connect(this, SIGNAL(error_str(QString)), this->parent(), SLOT(error_to_gui(QString)));    //发射者是this，不是tcpSocket。

//! [2] //! [3]

    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_0);
    //out << text;

    qDebug("new  connection");
    str_err= "new connection";
    emit error_str(str_err);

    /*状态机：等待密码 --> 等待索要数据 --> 发送数据 -->等待确认数据。
    */
    while(1){
        if(sta == Sta_server::WaitPwd){
            //在N秒内，要收到数据。
            if(false == tcpSocket.waitForReadyRead(5*1000)){
                str_err= "err: password timeout";
                emit error_str(str_err);

                qDebug()<< str_err; //qDebug(str_err); qDebug("%s", str_er); qDebug(str_err.toStdString());qDebug(str_err);

                return;
            }

            block= tcpSocket.readAll();

            qDebug("block size=%lld", block.size());
            if(6 == block.size()){
                //密码为6位
                if( ('L' == block.at(0))&&
                    ('J' == block.at(1))&&
                    ('m' == block.at(2))&&
                    ('a' == block.at(3))&&
                    ('o' == block.at(4))&&
                    ('k' == block.at(5)) ){
                    /*密码匹配，则准备数据，并将数据信息发送过去。
                    数据信息：包头（2B）+空格+长度字符串+空格+文件名称。
                    文件名由界面逐级传下来。
                    */
                    //file.setFileName("D:/DT45G_08008000_24.02.08.115554.bin");
                    file.setFileName(bin_file_name_path+ bin_file_name);
                    file.open(QIODeviceBase::ReadOnly);

                    QString str_size= QString("%1").arg(file.size());

                    QByteArray ba;
                    QDataStream out(&ba, QIODevice::WriteOnly);

                    out<<QString("XX"); //标识头。
                    out<<str_size;      //字符串：文件大小。也可为整数。
                    out<<bin_file_name; //字符串：文件名（不含路径）。

                    tot= 0;
                    tcpSocket.write(ba);

                    if(false == tcpSocket.waitForBytesWritten(2*1000)){
                        str_err="err:send data info";
                        emit error_str(str_err);

                        qDebug()<< str_err;
                        return;
                    }
                    qDebug()<<"sent data info";

                    sta= Sta_server::WaitAskData;
                }
                else{
                    str_err="err:password 1";
                    emit error_str(str_err);

                    qDebug()<< str_err;
                    return;
                }
            }
            else{
                str_err="err:password 2";
                emit error_str(str_err);

                qDebug()<< str_err;
                return;
            }
        }
        else if(sta == Sta_server::WaitAskData){
            //在N秒内，要收到数据。
            if(false == tcpSocket.waitForReadyRead(10*1000)){
                str_err="err: AskData timeout";
                emit error_str(str_err);

                qDebug()<< str_err;
                return;
            }
            block= tcpSocket.readAll();

            if(3== block.size()){
                //数据内容应ACK
                if( ('A'==block.at(0))&&
                    ('C'==block.at(1))&&
                    ('K'==block.at(2)) ){
                    str_err= "to sending data...";
                    emit error_str(str_err);

                    qDebug()<< str_err;

                    sta= Sta_server::SendingData;
                }
                else{
                    str_err= "err: ACK";
                    emit error_str(str_err);

                    return;
                }
            }
        }
        else if(sta == Sta_server::SendingData){
            QByteArray ba;

            ba= file.readAll();
            qDebug("start: %lld", QDateTime::currentMSecsSinceEpoch());

            tot= 0;
            tcpSocket.write(ba);

            if(false == tcpSocket.waitForBytesWritten(10*1000)){
                str_err= "err:send";
                emit error_str(str_err);

                return;
            }
            qDebug("end: %lld", QDateTime::currentMSecsSinceEpoch());
            qDebug("sent data");

            sta= Sta_server::WaitAckData;
        }
        else if(sta == Sta_server::WaitAckData){
            if(false == tcpSocket.waitForReadyRead(10*1000)){
                tcpSocket.close();
                str_err= "err: AckData timeout";
                emit error_str(str_err);

                return;
            }

            block= tcpSocket.readAll();
            if(2 == block.size()){
                if(('O' == block.at(0))&&
                   ('K' == block.at(1)) ){
                    str_err= "transfer ok, disconnect";
                    emit error_str(str_err);

                    return;
                }
            }
            else{
                str_err= "err:transfer";
                emit error_str(str_err);
                return;
            }
        }
    }//end of while(1)
}



void FortuneThread::DataWritten(qint64 bytes)
{
    QString str;

    str=QString::asprintf("cur= %lld,tot= %lld", bytes, tot+= bytes);
    emit error_str(str);

    qDebug()<< "DataWritten"<<str;
}



void FortuneThread::readFortune()
{
    //读取接收到的数据。
    //The most common example of a sequential device is a network socket
    qint64 cnt;
    //cnt= tcpSocket->bytesAvailable();
    qDebug("cnt= %lld", cnt);
    QByteArray ba;
    //ba= tcpSocket->readAll();

    tot+= cnt;
    qDebug("BAcnt= %lld, TOT= %lld", ba.size(), tot);

    return;
}

/*在这里处理错误信息。由于FortuneThread也不是GUI，所以只能转发给GUI。
 * 为什么用它呢？因为run()会退出吧。
*/
void FortuneThread::disp_err(QString err)
{
    qDebug()<<"to_gui:"<<err;     //输出err_to_gui 1: "err: password timeout"。QQ怎么有双引号呢？
    emit error_to_gui(err);
}
//! [4]
